package com.common.frame.base


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.HasDefaultViewModelProviderFactory
import androidx.lifecycle.ViewModelLazy
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.observe
import androidx.lifecycle.viewmodel.CreationExtras
import com.common.frame.BR
import com.common.frame.bean.MessageEvent
import com.common.frame.bean.TipsEvent
import com.common.frame.bean.ToastBean
import com.common.frame.listener.BindEventListener
import com.common.frame.widget.CustomToast
import com.common.frame.widget.LoadingDialog
import com.common.frame.widget.TipsDialog
import com.hjq.toast.ToastUtils
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.lang.reflect.ParameterizedType

abstract class BaseFragment<VM : BaseViewModel, VB : ViewDataBinding> : Fragment(),
    View.OnClickListener {

    lateinit var binding: VB

    val viewModel by initViewModel()

    private var loadingDialog: LoadingDialog? = null
    private var customToast: CustomToast? = null
    private var tipsDialog: TipsDialog? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = DataBindingUtil.inflate(inflater, layoutId(), container, false)
        registerViewModelChange()

        binding.setVariable(BR.viewModel, viewModel)

        binding.setVariable(BR.listener, this)

        binding.lifecycleOwner = this

        initData()
        initView()
        initObserve()
        initListener()

        if (this.javaClass.isAnnotationPresent(BindEventListener::class.java) && !EventBus.getDefault()
                .isRegistered(this)
        ) {
            EventBus.getDefault().register(this)
        }
        return binding.root
    }


    abstract fun layoutId(): Int
    abstract fun initData()
    abstract fun initView()

    open fun isUseActivityViewModel() = false
    open fun initListener() {

    }

    open fun initObserve() {

    }

    private fun Fragment.initViewModel(ownerProducer: () -> ViewModelStoreOwner = { this }): Lazy<VM> {
        val viewModelClass = getViewModelType().kotlin
        return ViewModelLazy(
            viewModelClass,
            { if (isUseActivityViewModel()) requireActivity().viewModelStore else ownerProducer().viewModelStore },
            {
                if (isUseActivityViewModel()) {
                    requireActivity().defaultViewModelProviderFactory
                } else {
                    (this as? HasDefaultViewModelProviderFactory)?.defaultViewModelProviderFactory
                        ?: defaultViewModelProviderFactory
                }
            },
            {
                if (isUseActivityViewModel()) {
                    requireActivity().defaultViewModelCreationExtras
                } else {
                    (this as? HasDefaultViewModelProviderFactory)?.defaultViewModelCreationExtras
                        ?: CreationExtras.Empty
                }
            })

    }

    /**
     * 获取viewModel类型
     */
    open fun getViewModelType(): Class<VM> {
        val modelClass: Class<VM>
        val type = javaClass.genericSuperclass
        modelClass = if (type is ParameterizedType) {
            type.actualTypeArguments[0] as Class<VM>
        } else {
            //如果没有指定泛型参数，则默认使用BaseViewModel
            BaseViewModel::class.java as Class<VM>
        }
        return modelClass
    }

    private fun registerViewModelChange() {
        viewModel.showLoadingDialog.observe(viewLifecycleOwner) { showLoading(it) }
        viewModel.dismissLoadingDialog.observe(viewLifecycleOwner) { dismissLoading() }

        viewModel.toastEvent.observe(viewLifecycleOwner) {
            ToastUtils.show(it)
        }
        viewModel.dataEvent.observe(viewLifecycleOwner) {
            handleEvent(it.action, it.result)
        }
        viewModel.customToastEvent.observe(viewLifecycleOwner) {
            showToast(it)
        }
        viewModel.tipsEvent.observe(viewLifecycleOwner) {
            showTips(it)
        }
    }

    open fun handleEvent(action: String, result: Any) {}

    override fun onClick(v: View) {

    }

    fun showLoading(text: String) {
        loadingDialog ?: let {
            loadingDialog = LoadingDialog(requireContext())
        }
        loadingDialog?.show()
        loadingDialog?.setTips(text)


    }

    fun dismissLoading() {
        loadingDialog?.let {
            if (it.isShowing) it.dismiss()
        }
    }

    fun showToast(item: ToastBean) {
        customToast ?: let {
            customToast = CustomToast(requireContext())
        }
        customToast?.setText(item.msg)
        customToast?.showToast(item.duration)
    }

    fun showTips(event: TipsEvent) {
        tipsDialog ?: let {
            tipsDialog = TipsDialog(requireContext()).apply {
                listener = {
                    onTipsEvent(it)
                }
            }
        }
        tipsDialog?.show(event)
    }

    open fun onTipsEvent(event: TipsEvent) {

    }

    override fun onDestroy() {

        if (this.javaClass.isAnnotationPresent(BindEventListener::class.java) && EventBus.getDefault()
                .isRegistered(this)
        ) {
            EventBus.getDefault().unregister(this)
        }

        super.onDestroy()
    }


    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(msg: MessageEvent) {
        onReceiveEvent(msg)
    }

    open fun onReceiveEvent(msg: MessageEvent) {

    }


}